
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <webkit/webkit.h>
#include <amanita/aMath.h>
#include "../Main.h"
#include "../Profile.h"
#include "../TextPage.h"
#include "Horoscope.h"
#include "HoroscopeChartPage.h"
#include "../occult/Occult.h"
//#include "..\TextMDI.h"


extern int rulingPlanets[];

extern int aspectRatios[];
extern int aspectSigns[];
extern int aspectOrbs[13][4];
extern int aspectIndex[2][6];

extern int QualityData[];
extern int ElementData[];
extern int EnergyData[];
extern double PlanetData[];


float HoroscopeChartPage::planetSizes[11] = { 0.03,0.08,0.01,0.02,0.03,0.02,0.04,0.05,0.05,0.04,0.02 };
float HoroscopeChartPage::planetDistances[11] = { 0.35,0,0.07,0.15,0.25,0.45,0.55,0.65,0.75,0.85,0.95 };

bool HoroscopeChartPage::aspectShow[23] = { true,false,false,false,false,false,true,false,true,true,false,false,true,false,true,true,true,true,true,true,true,true,true };


const double HoroscopeChartPage::circle = aMath::PI*2;
const double HoroscopeChartPage::trine = aMath::PI*2/3;
const double HoroscopeChartPage::step = -aMath::PI/6;
const double HoroscopeChartPage::half = -aMath::PI/12;


void HoroscopeChartPage::webview_hover_event_callback(WebKitWebView *webview,gchar *title,gchar *uri,gpointer data) {
	app.handleAction(ACTION_SHOW_STATUS,0,(void *)(uri? uri : aString::blank));
}

gboolean HoroscopeChartPage::webview_navigation_decision_event_callback(WebKitWebView *webview,WebKitWebFrame *frame,WebKitNetworkRequest *request,
																	WebKitWebNavigationAction *action,WebKitWebPolicyDecision *decision,gpointer data) {
	int reason = webkit_web_navigation_action_get_reason(action);
	if(reason>=WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED && reason<=WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED) {
//		const gchar *uri = webkit_web_navigation_action_get_original_uri(action);
		const gchar *uri = webkit_network_request_get_uri(request);
app.printf("HoroscopeChartPage::webview_navigation_decision_event_callback(uri=\"%s\",reason=%d)",uri,reason);
		webkit_web_policy_decision_ignore(decision);
		new TextPage(uri);
		app.handleAction(ACTION_SHOW_STATUS,0,(void *)aString::blank);
		return TRUE;
	} else return FALSE;
}

/*gboolean HoroscopeChartPage::webview_navigation_event_callback(WebKitWebView *webview,WebKitWebFrame *frame,WebKitNetworkRequest *request,gpointer data) {
	const gchar *uri = webkit_network_request_get_uri(request);
app.printf("HoroscopeChartPage::webview_navigation_event_callback(uri=\"%s\")",uri);
	new TextPage(uri);
	app.handleAction(ACTION_SHOW_STATUS,0,(void *)aString::blank);
	return TRUE;
}*/

gboolean HoroscopeChartPage::graph_configure_event_callback(GtkWidget *widget,GdkEventConfigure *event,gpointer data) {
	HoroscopeChartPage &page = *(HoroscopeChartPage *)data;
	page.gtk.graph.x = 0;
	page.gtk.graph.y = 0;
	page.gtk.graph.width = gtk_widget_get_allocated_width(widget);
	page.gtk.graph.height = gtk_widget_get_allocated_height(widget);
	return TRUE;
}

gboolean HoroscopeChartPage::graph_expose_event_callback(GtkWidget *widget,GdkEventExpose *event,gpointer data) {
	HoroscopeChartPage &page = *(HoroscopeChartPage *)data;
	page.paint();
	return TRUE;
}

HoroscopeChartPage::HoroscopeChartPage(Horoscope *h) : Page() {
app.printf("HoroscopeChartPage::HoroscopeChartPage(%s)",h->profile.name());
	horoscope = h;
	counter = 0;
	planetHover = -1;
	planetFocus = 0;
	focus = false;

	aString str;
	writeHoroscope(str);

	GtkWidget *page = gtk_table_new(2,1,FALSE);

	GtkWidget *scroll = gtk_scrolled_window_new(NULL,NULL);
	gtk_widget_set_size_request(scroll,360,-1);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),GTK_POLICY_AUTOMATIC,GTK_POLICY_ALWAYS);
	//gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),GTK_SHADOW_IN);
	gtk.webview = webkit_web_view_new();
	WebKitWebSettings *settings = webkit_web_settings_new();
	g_object_set(settings,
			"auto-load-images",TRUE,
			"auto-shrink-images",FALSE,
			"default-encoding","UTF-8",
			"enable-plugins",FALSE,
		NULL);
	webkit_web_view_set_settings(WEBKIT_WEB_VIEW(gtk.webview),settings);
	char base[256];
	sprintf(base,"file://%s",app.getHomeDir());
	webkit_web_view_load_string(WEBKIT_WEB_VIEW(gtk.webview),str.toCharArray(),"text/html","UTF-8",base);
	g_signal_connect(G_OBJECT(gtk.webview),"hovering-over-link",G_CALLBACK(webview_hover_event_callback),this);
	g_signal_connect(G_OBJECT(gtk.webview),"navigation-policy-decision-requested",G_CALLBACK(webview_navigation_decision_event_callback),this);
//	g_signal_connect(G_OBJECT(gtk.webview),"navigation-requested",G_CALLBACK(webview_navigation_event_callback),this);
	gtk_container_add(GTK_CONTAINER(scroll),gtk.webview);
	gtk_table_attach(GTK_TABLE(page),scroll,0,1,0,1,
		(GtkAttachOptions)(GTK_FILL|GTK_SHRINK),(GtkAttachOptions)(GTK_FILL|GTK_EXPAND),2,2);

	gtk.graph_area = gtk_drawing_area_new();
	g_signal_connect(G_OBJECT(gtk.graph_area),"configure_event",G_CALLBACK(graph_configure_event_callback),this);
	g_signal_connect(G_OBJECT(gtk.graph_area),"expose_event",G_CALLBACK(graph_expose_event_callback),this);
	gtk_table_attach(GTK_TABLE(page),gtk.graph_area,1,2,0,1,
		(GtkAttachOptions)(GTK_FILL|GTK_EXPAND),(GtkAttachOptions)(GTK_FILL|GTK_EXPAND),2,2);

	Page::open(h->profile.name(),page);

FILE *fp = fopen("index.html","w");
fprintf(fp,"%s",str.toCharArray());
fclose(fp);
}

HoroscopeChartPage::~HoroscopeChartPage() {
app.printf("HoroscopeChartPage::~HoroscopeChartPage()");
	if(horoscope) { delete horoscope;horoscope = 0; }
}

void HoroscopeChartPage::paint() {
app.printf("HoroscopeChartPage::paint()");
	int x = 5,y = 14;
	graphSize = gtk.graph.width-(x*2);
	if(gtk.graph.height-(y*2)<graphSize) graphSize = gtk.graph.height-(y*2);
	if(graphSize<300) graphSize = 300;

	ascendant = horoscope->houseCusp(1);

	switch(horoscope->style()) {
		case HOROSCOPE_NATAL:paintNatal();break;
		case HOROSCOPE_SOLARSYS:paintSolarSystem();break;
		case HOROSCOPE_SYNASTRY:paintSynastry();break;
		case HOROSCOPE_COMPOSITE:paintComposite();break;
	}

}

/*
#define CHART_CONTENT_RING			0
#define CHART_CONTENT_RULER		1
#define CHART_CONTENT_ELEMENTS	2
#define CHART_CONTENT_ZODIAC		3
#define CHART_CONTENT_PLANETS		4
#define CHART_CONTENT_HOUSES		5

	struct graph_content {
		int type;
		double angle;
		int p1,p2,p3,p4;
		int color[4];
	};

	struct graph_style {
		double size;
		int ncontent;
		graph_content content[10];
	};
*/
void HoroscopeChartPage::paintNatal() {
	Horoscope &h = *horoscope;
	clearPlanetLocations(h,planetLocations1,planetAngles1);
	double a = DTR*ascendant;

	int planets[11] = { 0x0000ff,0xffff00,0xff99ff,0xff6600,0xffcc00,0xff0000,0xff9966,0xffcc99,0x9999ff,0x99ccff,0xff66ff };
	int elements[5] = { 0x660000,0x006600,0x666600,0x000066 };
	int zodiac[13] = { 0xff0000,0x00cc00,0xffff00,0x0000ff,0xff0000,0x00cc00,0xffff00,0x0000ff,0xff0000,0x00cc00,0xffff00,0x0000ff };
	int aspects[13] = { 0x00ff00,0xcc0099,0x00cc99,0xcccc00,0xcc0000,0x99cc00,0x00cc00,0xcc9900,0xff0000,0x0000ff,0xff0099,0xff0099,0xcc9900 };
//	int orbits[11] = { 0x000033,0x333300,0x330033,0x330000,0x330000,0x330000,0x330000,0x330000,0x000033,0x000033,0x330033 };

	graph_content gc[] = {
		{CHART_CONTENT_RING,					0,		1,0,0,0,			{0x000011,-1}},
		{CHART_CONTENT_RING,					0,		1,0,0,0,			{0x000011,0x000099}},
		{CHART_CONTENT_RULER,				-a,	1,-1,-4,1,		{0x3333ff}},
		{CHART_CONTENT_RULER,				-a,	10,-1,-10,1,	{0x6666ff}},

		{CHART_CONTENT_RING,					0,		1,0,0,0,			{0x000011,0xffffff}},
		{CHART_CONTENT_ASPECTS,				-a,	5,0,0,0,			{}},

		{CHART_CONTENT_RING,					0,		1,0,0,0,			{0x000011,-1}},
		{CHART_CONTENT_ELEMENTS,			-a,	0,0,0,0,			{}},
		{CHART_CONTENT_ZODIAC,				-a,	26,0,0,0,		{0x000011}},
		{CHART_CONTENT_RULER,				-a,	30,0,40,2,		{0x000011}},

		{CHART_CONTENT_RING,					0,		1,0,0,0,			{0x000011,0x3333ff}},
		{CHART_CONTENT_HOUSES,				-a,	2,0,0,0,			{0x663300}},
		{CHART_CONTENT_ASC_MC_ARROW,		-a,	34,13,16,13,	{0x663300,0x663300,0xffcc99}},
		{CHART_CONTENT_PLANETS,				-a,	24,20,2,0,		{0xffcc99,0x000033,0xcc9966}},

	};

	graph_level gl[] = {
		{4,		1,&gc[1]},
		{40,		4,&gc[6]},
		{10,		3,&gc[1]},
		{60.3,	4,&gc[10]},
		{4,		1,&gc[0]},
		{0,		2,&gc[4]},
	};

	graph_style gs = {
		14,14,gtk.graph.width-28,gtk.graph.height-28,
		-1,
		elements,
		zodiac,
		planets,
		aspects,
		6,gl
	};

	cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(gtk.graph_area));
	setColor(cr,0x000066);
	cairo_rectangle(cr,0,0,gtk.graph.width,gtk.graph.height);
	cairo_fill(cr);
	cairo_stroke_preserve(cr);
	//int radies[] = { c,c-44,c-104 };
	//int style[] = { 1|8|(4<<8),4|(4<<4)|8|(5<<8),2|4 };
	//int r1 = radies[1],r2 = radies[2];
	paintGraph(cr,gs);
	//paintGraph(30,radies,style,3);
	//paintHouses(17,r1,r2,r2,r1,h,colors[2],colors[1]);
	//paintPlanets(24,r2+4,r2+18,r2+38,h,planetLocations1,planetAngles1,colors[1]);
	//paintAspects(r2-3,h,h,false);
	cairo_stroke(cr);
	cairo_destroy(cr);
}

void HoroscopeChartPage::paintSolarSystem() {
/*
	Horoscope &h = *horoscope;
	clearPlanetLocations(h,planetLocations1);
	int c = graphSize>>1,x = graph.x+((graph.width-graphSize)>>1),y = graph.y+((graph.height-graphSize)>>1);
	if(x<graph.x) x = graph.x;
	if(y<graph.y) y = graph.y;
	xc = x+c,yc = y+c;
	int fs = 24,r1 = c-2,r2 = c-fs-4,r3 = c-(fs<<1)-20;
	char str[2] = {0,0};
	int d = r2+((r1-r2+fs)>>1);
	double asc = DTR*ascendant,a = 0,a2 = ((double)d/(fs*300.0));
	GdkPixbuf &img = *images[1];
	setColor(gfx->hdc,colors[4]);
	setBackground(gfx->hdc,colors[5]);
	Ellipse(gfx->hdc,xc-c,yc-c,xc+c,yc+c);

	int set[11],dists[11],sizes[11];
	double hlon[11],glon[11];
	memset(hlon,0,11*8);
	for(int i=0,p; i<=h.planets(); i++) {
		p = i<h.planets()? h.planetID(i) : ASTRO_TELLUS;
		if(p<=ASTRO_PLUTO) {
			dists[p] = aMath::round(planetDistances[p]*r3),sizes[p] = aMath::round(planetSizes[p]*r3);
			if(p!=ASTRO_TELLUS) set[p] = i+1,
				hlon[p] = asc-DTR*h.heliocentric(i),
					glon[p] = asc-DTR*h.planetLongitude(i);
		}
	}
	if(set[ASTRO_SUN]) set[ASTRO_TELLUS] = 1,
		hlon[ASTRO_TELLUS] = asc-DTR*h.heliocentric(set[ASTRO_SUN]-1);
	for(int i=ASTRO_TELLUS; i<=ASTRO_PLUTO; i++) if(set[i]) {
		if(i==ASTRO_SUN) planetLocations1[i] = (GdkRectangle){ xc-sizes[i],yc-sizes[i],sizes[i]*2,sizes[i]*2 };
		else {
			a = hlon[i];
			if(i!=ASTRO_MOON) planetLocations1[i] = (GdkRectangle){ xc-aMath::round(planetDistances[i]*r3*cos(a))-sizes[i],yc-aMath::round(planetDistances[i]*r3*sin(a))-sizes[i],sizes[i]*2,sizes[i]*2 };
			else planetLocations1[i] = (GdkRectangle){ planetLocations1[ASTRO_TELLUS].x+sizes[ASTRO_TELLUS]-aMath::round(planetDistances[i]*r3*cos(a))-sizes[i],planetLocations1[ASTRO_TELLUS].y+sizes[ASTRO_TELLUS]-aMath::round(planetDistances[i]*r3*sin(a))-sizes[i],sizes[i]*2,sizes[i]*2 };
		}
	}

	int tx = planetLocations1[ASTRO_TELLUS].x+sizes[ASTRO_TELLUS],ty = planetLocations1[ASTRO_TELLUS].y+sizes[ASTRO_TELLUS];
	setBackground(gfx->hdc,-1);
	for(int i=ASTRO_TELLUS,px,py; i<=ASTRO_PLUTO; i++) if(set[i]) {
		setColor(gfx->hdc,orbitColors[i]);
		if(i!=ASTRO_SUN) {
			if(i==ASTRO_MOON) {
				if(!set[ASTRO_TELLUS]) continue;
				px = tx,py = ty;
			} else px = xc,py = yc;
			Ellipse(gfx->hdc,px-dists[i],py-dists[i],px+dists[i],py+dists[i]);
		}
//		if(i!=ASTRO_TELLUS) {
//			drawLine(tx,ty,px=(planetLocations1[i].x+sizes[i]),py=(planetLocations1[i].y+sizes[i]));
//			drawLine(px,py,xc-aMath::round(r3*cos(glon[i])),yc-aMath::round(r3*sin(glon[i])));
//		}
	}
	setColor(gfx->hdc,-1);
	for(int i=ASTRO_TELLUS,px,py; i<=ASTRO_PLUTO; i++) if(set[i]) {
		setBackground(gfx->hdc,planetColors[i]);
		px = planetLocations1[i].x,py = planetLocations1[i].y;
		Ellipse(gfx->hdc,px,py,px+planetLocations1[i].width,py+planetLocations1[i].height);
	}

	a = asc;
	for(int i=ASTRO_ARIES; i<=ASTRO_PISCES; i++) {
		a += half,*str = 'A'+i-ASTRO_ARIES;;
		aGraphics::setFont(gfx->hdc,getFont(FW_BOLD,fs,"HorusEye Astro",(900-aMath::round(RTD*a*10)+3600)%3600));
		setTextColor(gfx->hdc,elementColors[(i-1)%4+1]);
		TextOut(gfx->hdc,xc-aMath::round(cos(a-a2)*d),yc-aMath::round(sin(a-a2)*d),str,1);
		a += half;
		if(a<=0) a += circle;
	}

	paintPlanets(fs,r3,r3+8,r3+20,h,planetLocations1,planetAngles1,colors[1]);
*/
}

void HoroscopeChartPage::paintSynastry() {
/*
	if(!horoscope->rels[1]) { paintNatal();return; }
	Horoscope &h1 = *horoscope,&h2 = *h1.rels[1];
	clearPlanetLocations(h1,planetLocations1,planetAngles1);
	clearPlanetLocations(h2,planetLocations2,planetAngles2);
	int c = graphSize>>1,x = graph.x+((graph.width-graphSize)>>1),y = graph.y+((graph.height-graphSize)>>1);
	xc = (x<graph.x? graph.x : x)+c,yc = (y<graph.y? graph.y : y)+c;
	int radies[] = { c,c-44,c-87,c-130 };
	int style[] = { 1|8|(4<<8),4|(4<<4)|8|(5<<8),0,2|4 };
	int r = radies[2];
	paintGraph(30,radies,style,4);
	paintHouses(17,radies[1],radies[2],radies[2],radies[1],h1,colors[2],colors[1]);
	paintHouses(17,radies[2],radies[3],radies[3],radies[3],h2,colors[2],colors[1]);
	paintPlanets(24,r+4,r+12,r+26,h1,planetLocations1,planetAngles1,aspectColors[1]);
	paintPlanets(24,r-4,r-12,r-26,h2,planetLocations2,planetAngles2,aspectColors[2]);
	paintAspects(radies[3]-2,h1,h2,true);
*/
}

void HoroscopeChartPage::paintComposite() {
/*
	paintNatal();
*/
}

void HoroscopeChartPage::paintGraph(cairo_t *cr,graph_style &gs) {
	Horoscope &h = *horoscope;
	int i,j,k,l,m,n,r/*,x,y*/;
	double d;

	int size = gs.height<gs.width? gs.height : gs.width;
	int radius = size/2,xc = gs.x+(gs.width-size)/2+radius,yc = gs.y+(gs.height-size)/2+radius;

	{
		h.planets();
		i=0,j=0,k=0,l=0,m=0,n=0,r=0/*,x=0,y=0*/,d=0.0;
	}

	cairo_save(cr);

	/* Paint background */
	for(i=0,m=0; i<gs.nlevels; i++,m+=n) {
		graph_level &gl = gs.levels[i];
		n = (int)gl.size;
		if(gl.size-(double)n>0.0) {
			n = aMath::round((double)radius*(gl.size-(double)n));
			if(n<(int)gl.size) n = (int)gl.size;
		} else n = aMath::round(gl.size);
		r = radius-m;
		for(j=0; j<gl.ncontent; j++) {
			graph_content &gc = gl.content[j];
			switch(gc.type) {
				case CHART_CONTENT_RING:
					if(gc.color[1]!=-1) {
						setColor(cr,gc.color[1]);
						cairo_arc(cr,xc,yc,r-1,0.0,M_PI*2.0);
						cairo_close_path(cr);
						cairo_stroke_preserve(cr);
						cairo_fill(cr);
						cairo_stroke(cr);
					}
					break;

				case CHART_CONTENT_ELEMENTS:
					for(k=0; k<12; k++) {
//						if(k==0) setColor(0x000000);
//						else
						setColor(cr,gs.element_colors[(k%4)+1]);
						d = gc.angle+DTR*((double)k*30.0+90.0);
						cairo_arc(cr,xc,yc,r-1,-d,-d+M_PI/6.0);
						cairo_line_to(cr,xc,yc);
						cairo_close_path(cr);
						cairo_stroke_preserve(cr);
						cairo_fill(cr);
						cairo_stroke(cr);
					}
					break;
			}
		}
	}

	/* Paint foreground */
	for(i=0,m=0; i<gs.nlevels; i++,m+=n) {
		graph_level &gl = gs.levels[i];
		n = (int)gl.size;
		if(gl.size-(double)n>0.0) {
			n = aMath::round((double)radius*(gl.size-(double)n));
			if(n<(int)gl.size) n = (int)gl.size;
		} else n = aMath::round(gl.size);
		r = radius-m;
		for(j=0; j<gl.ncontent; j++) {
			graph_content &gc = gl.content[j];
			switch(gc.type) {
				case CHART_CONTENT_RING:
					if(gc.color[0]!=-1 && gc.color[0]!=gc.color[1]) {
						cairo_set_line_width(cr,(double)gc.p1);
						setColor(cr,gc.color[0]);
						cairo_arc(cr,xc,yc,r,0.0,M_PI*2.0);
						cairo_close_path(cr);
						cairo_stroke(cr);
					}
					break;

				case CHART_CONTENT_RULER:
//app.printf("HoroscopeChartPage::paintGraph(CHART_CONTENT_RULER,c.p1=%d)",c.p1);
					setColor(cr,gc.color[0]);
					cairo_set_line_width(cr,(double)gc.p4);
					for(k=0; k<360; k+=gc.p1) {
//app.printf("HoroscopeChartPage::paintGraph(k=%d)",k);
						for(l=0; l<gl.ncontent; l++)
							if(j!=l && gl.content[l].type==CHART_CONTENT_RULER
									&& gc.p1<gl.content[l].p1 && (k%gl.content[l].p1)==0) {
//app.printf("HoroscopeChartPage::paintGraph(skip)");
								goto paint_ruler_next;
							}
						l = r+(gc.p3<0? -n : 0);
						d = gc.angle+DTR*(double)k;
						cairo_move_to(cr,xc-aMath::round(cos(-d)*(l-gc.p2)),yc-aMath::round(sin(-d)*(l-gc.p2)));
						cairo_line_to(cr,xc-aMath::round(cos(-d)*(l-gc.p3)),yc-aMath::round(sin(-d)*(l-gc.p3)));
						cairo_stroke(cr);

paint_ruler_next:
						;
					}
					break;

				case CHART_CONTENT_ZODIAC:
				{
					cairo_save(cr);
					char str[32];
					cairo_select_font_face(cr,"Mantichora Astro",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL);
					cairo_set_font_size(cr,gc.p1);

					l = r-n/2;
					d = gc.angle+DTR*(90.0-15.0);

					cairo_save(cr);
					cairo_translate(cr,xc+1,yc+1);
					cairo_rotate(cr,-d);
					setColor(cr,gc.color[0]);
					for(k=ASTRO_ARIES,str[1]='\0'; k<=ASTRO_PISCES; k++) {
						cairo_rotate(cr,-(aMath::PI/6.0));
						cairo_move_to(cr,-12,12-l);
						*str = 'A'+k-ASTRO_ARIES;
						cairo_show_text(cr,str);
					}
					cairo_restore(cr);

					cairo_translate(cr,xc-1,yc-1);
					cairo_rotate(cr,-d);
					for(k=ASTRO_ARIES,str[1]='\0'; k<=ASTRO_PISCES; k++) {
						setColor(cr,gs.zodiac_colors[k]);
						cairo_rotate(cr,-(aMath::PI/6.0));
						cairo_move_to(cr,-12,12-l);
						*str = 'A'+k-ASTRO_ARIES;
						cairo_show_text(cr,str);
					}
					cairo_restore(cr);
					break;
				}

				case CHART_CONTENT_HOUSES:
				{
//app.printf("HoroscopeChartPage::paintGraph(CHART_CONTENT_RULER,c.p1=%d)",c.p1);
					cairo_set_line_width(cr,(double)gc.p1);
					setColor(cr,gc.color[0]);
					for(k=1; k<=12; k++) {
						d = gc.angle+DTR*h.houseCusp(k);
//app.printf("HoroscopeChartPage::paintGraph(CHART_CONTENT_HOUSES,d=%f)",d);
						cairo_move_to(cr,xc-aMath::round(cos(-d)*r),yc-aMath::round(sin(-d)*r));
						cairo_line_to(cr,xc-aMath::round(cos(-d)*(r-n)),yc-aMath::round(sin(-d)*(r-n)));
						cairo_stroke(cr);
					}
					break;
				}

				case CHART_CONTENT_ASC_MC_ARROW:
				{
					char str[32];
					cairo_set_line_width(cr,3.0);
					cairo_select_font_face(cr,"Mantichora Astro",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL);

					setColor(cr,gc.color[1]);
					for(k=0,str[1]='\0'; k<2; k++) {
						d = gc.angle+DTR*h.houseCusp(k==0? 1 : 10);
						cairo_move_to(cr,xc-aMath::round(cos(-d)*(r-n)),yc-aMath::round(sin(-d)*(r-n)));
						cairo_line_to(cr,xc-aMath::round(cos(-d)*(r+gc.p2+gc.p1/2)),yc-aMath::round(sin(-d)*(r+gc.p2+gc.p1/2)));
						cairo_stroke(cr);
					}

					cairo_save(cr);
					str[1]='\0';
					setColor(cr,gc.color[0]);
					cairo_set_font_size(cr,gc.p1);
					*str = '<';
					for(k=0; k<2; k++) {
						cairo_save(cr);
						l = r+gc.p2+gc.p1*2;
						d = gc.angle+DTR*h.houseCusp(k==0? 1 : 10)+atan2((double)gc.p1/2.775,r+gc.p2+gc.p1);
						cairo_translate(cr,xc-aMath::round(cos(-d)*l),yc-aMath::round(sin(-d)*l));
						cairo_move_to(cr,0,0);
						cairo_rotate(cr,aMath::PI*2.0-(gc.angle+DTR*h.houseCusp(k==0? 1 : 10)));
						cairo_show_text(cr,str);
						cairo_restore(cr);

/*						bool s = abs(180-aMath::round(d*RTD))%360>=90;
app.printf("a1=%d,a2=%d,s=%d",abs(180-aMath::round(d*RTD))%360,90,s);
						*str = 'a'+(k==0? ASTRO_ASCENDANT : ASTRO_MC);
						l = r+gc.p4+(s? gc.p3 : 0);
						//d += s? 0.1+atan2((double)c.p2/1.63,l) : 0.1;
						d = gc.angle+DTR*h.houseCusp(k==0? 1 : 10)+(s? atan2((double)gc.p3/2.0,l) : -atan2((double)gc.p3/2.0,l));
//						planetLocations1[n] = (GdkRectangle){ xc-aMath::round(cos(a)*r),yc-aMath::round(sin(a)*r),fs,fs };
						paintText(xc-aMath::round(cos(-d)*l),yc-aMath::round(sin(-d)*l),aMath::PI*(s? 1.99 : 0.99)-d,str,font2,gc.color[2]);*/
					}
					cairo_restore(cr);
					break;
				}

				case CHART_CONTENT_PLANETS:
				{
					char str[32];
					cairo_set_line_width(cr,0.5);
					cairo_select_font_face(cr,"Mantichora Astro",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL);
					cairo_set_font_size(cr,gc.p1);


					clearPlanetLocations(h,planetLocations1,planetAngles1);
					l = aMath::round((aMath::PI*(r-n))/h.planets())+1;
					for(k=0; k<h.planets(); k++) positionPlanet(k,planetLocations1,planetAngles1,0.0,gc.p1,r-gc.p2+(gc.p2<0? gc.p1/2 : -gc.p1/2),h,k,l);

					for(k=0,str[1]='\0'; k<h.planets(); k++) {
						l = h.planetID(k);
						if(l==ASTRO_ASCENDANT || l==ASTRO_MC) continue;
						*str = 'a'+l;

						setColor(cr,gc.color[2]);
						l = r-gc.p2+(gc.p2<0? -5 : 5);
						d = gc.angle+DTR*h.planetLongitude(k);
						cairo_move_to(cr,xc-aMath::round(cos(-d)*(r-gc.p3)),yc-aMath::round(sin(-d)*(r-gc.p3)));
						cairo_line_to(cr,xc-aMath::round(cos(planetAngles1[k])*l),yc-aMath::round(sin(planetAngles1[k])*l));
						cairo_stroke(cr);

//app.printf("planetLocations1[x=%d,y=%d,a=%f]",planetLocations1[k].x,planetLocations1[k].y,planetAngles1[k]);
//						paintText(xc+planetLocations1[k].x,yc+planetLocations1[k].y,0.0,str,font,c.color[0]);
						setColor(cr,gc.color[1]);
						cairo_move_to(cr,xc+planetLocations1[k].x+1,yc+planetLocations1[k].y+gc.p1+1);
						cairo_show_text(cr,str);
						setColor(cr,gc.color[0]);
						cairo_move_to(cr,xc+planetLocations1[k].x-1,yc+planetLocations1[k].y+gc.p1-1);
						cairo_show_text(cr,str);
					}
					cairo_stroke(cr);
					break;
				}

				case CHART_CONTENT_ASPECTS:
				{
					int a;
					double p1,p2;
					for(k=1; k<h.planets(); k++)
						for(l=0; l<k; l++) {
							a = h.aspect(k,l);
							if(a>=ASTRO_CONJUNCTION && a<=ASTRO_OPPOSITION && aspectShow[a] &&
									(!aspectShow[13] || horoscope->findPattern(k,l))) {
								setColor(cr,gs.aspect_colors[a]);
								p1 = gc.angle+DTR*h.planetLongitude(k);
								p2 = gc.angle+DTR*h.planetLongitude(l);
								cairo_move_to(cr,xc-aMath::round(cos(-p1)*(r-gc.p1)),yc-aMath::round(sin(-p1)*(r-gc.p1)));
								cairo_line_to(cr,xc-aMath::round(cos(-p2)*(r-gc.p1)),yc-aMath::round(sin(-p2)*(r-gc.p1)));
								cairo_stroke(cr);
							}
						}
					break;
				}
			}
		}
	}
}


void HoroscopeChartPage::paintGraph(int fs,int *rings,int *style,int len,int offset) {
/*
	double asc = DTR*ascendant,a = asc;
	//char str[2] = {0,0};
//	GdkPixbuf &img = *images[1];
//	GdkPixbuf &cimg = *images[5];
	memset(&zodiacLocations,0,sizeof(zodiacLocations));
	for(int i=offset,e,n,r1=rings[i],s; i<offset+len; r1=rings[++i]) {
		s = style[i];
		if(s&8) setFGColor(colors[(s>>8)&0xf]);
		if(s&1) {
			//int r2 = i+1<offset+len? rings[i+1] : 0,d1 = r2+((r1-r2)>>1),d2 = r2+((r1-r2+fs)>>1);
			//double a2 = ((double)d2/(fs*300.0));
//fprintf(out,"HoroscopeChartPage::paintGraph(r1=%d,r2=%d,d=%d,a2=%lf)\n",r1,r2,d,a2);
			for(a=asc,e=ASTRO_FIRE; e<=ASTRO_WATER; e++) {
				setFGColor(elementColors[e]);
				for(n=0; n<3; n++,a+=trine)
					gdk_draw_arc(gtk.graph_image,gtk.graph_gc,TRUE,xc-r1,yc-r1,r1*2,r1*2,64*RTD*a,64*RTD*(a+step));
				a = asc+e*step;
			}
			for(a=asc,e=ASTRO_ARIES; e<=ASTRO_PISCES; e++) {
				a += half,*str = 'A'+e-ASTRO_ARIES;
				aGraphics::setFont(gfx->hdc,getFont(FW_BOLD,fs,"HorusEye Astro",(900-aMath::round(RTD*a*10)+3600)%3600));
				setTextColor(gfx->hdc,zodiacColors[e]);
				zodiacLocations[e] = (GdkRectangle){ xc-aMath::round(cos(a)*d1)-(fs>>1),yc-aMath::round(sin(a)*d1)-(fs>>1),fs,fs };
				TextOut(gfx->hdc,xc-aMath::round(cos(a-a2)*d2),yc-aMath::round(sin(a-a2)*d2),str,1);
				a += half;
				if(a<=0) a += circle;
			}
			setFGColor(colors[4]);
		} else if(s&4) {
			setFGColor(colors[(s>>4)&0xf]);
			gdk_draw_arc(gtk.graph_image,gtk.graph_gc,FALSE,xc-r1,yc-r1,r1*2,r1*2,0,64*360);
		} else gdk_draw_arc(gtk.graph_image,gtk.graph_gc,FALSE,xc-r1,yc-r1,r1*2,r1*2,0,64*360);
		//if(s&2) drawImage(cimg,xc-cimg.hw,yc-cimg.hh,cimg.w,cimg.h,0,0);
	}
*/
}

void HoroscopeChartPage::paintHouses(int fs,int r0,int r1,int r2,int r3,Horoscope &h,int c1,int c2) {
/*
	int i,fsa = 50;;
	double asc = ascendant,angle,a,an[13],r4;
	char str[10];
	aGraphics::setFont(gfx->hdc,getFont(FW_NORMAL,12,"Arial"));
	setTextColor(gfx->hdc,c1);
	setColor(gfx->hdc,c1);
	for(int i=1; i<=12; i++) {
		a = an[i] = aMath::PI*((asc-h.houseCusp(i))/180);
		sectorLine(xc,yc,(double)r0,(double)r1,a);
		sprintf(str,"%d",i);
		TextOut(gfx->hdc,xc-(i>9? 6 : 0)-aMath::round((r2+9)*cos(a-0.05)),yc+(i<=6? -2 : -5)-aMath::round((r2+9)*sin(a-0.05)),str,i<10? 1 : 2);
	}
	for(int i=1; i<=12; i++) {
		if(i==1 || i==4 || i==7 || i==10) {
			angle = an[i];
			setColor(gfx->hdc,0,4);
			sectorLine(xc,yc,(double)r1,(double)(r3+(i==1 || i==10? fs+18 : 0)),angle);
			if(i==1 || i==10) {
				setTextColor(gfx->hdc,0);
				aGraphics::setFont(gfx->hdc,getFont(FW_BOLD,fsa,"HorusEye Astro",(1800-aMath::round(RTD*angle*10)+1800)%3600));
				r4 = r3+fs+18+fsa,a = angle+atan((fsa/2.0)/r4),*str = '<';
				TextOut(gfx->hdc,xc-aMath::round(r4*cos(a)),yc-aMath::round(r4*sin(a)),str,1);

				setTextColor(gfx->hdc,c2);
				bool s = abs(180-aMath::round(angle*RTD))%360>=90;
//fprintf(out,"a1=%d,a2=%d,s=%d\r\n",abs(180-aMath::round(a*RTD))%360,90,s);
				int n = i==1? ASTRO_ASCENDANT : ASTRO_MC,r = r3+fs+6-(s? 3 : 3+fs);
				a = angle+(s? -0.02 : 0.02),*str = 'a'+n;
				planetLocations1[n] = (GdkRectangle){ xc-aMath::round(cos(a)*r),yc-aMath::round(sin(a)*r),fs,fs };
				aGraphics::setFont(gfx->hdc,getFont(FW_BOLD,fs,"HorusEye Astro",(1800-aMath::round(RTD*a*10)+(s? 1800 : 3600))%3600));
				TextOut(gfx->hdc,planetLocations1[n].x,planetLocations1[n].y,str,1);
			}
		}
	}
*/
}

void HoroscopeChartPage::paintPlanets(int fs,int r1,int r2,int r3,Horoscope &h,GdkRectangle *pl,double *pa,int c) {
/*
	int i,p,fs2 = fs>>1,fs3 = fs/10;
	double asc = ascendant,a1,a2;
	char str[4] = {0,0,0,0};
	aGraphics::setFont(gfx->hdc,getFont(FW_BOLD,fs,"HorusEye Astro"));
	setTextColor(gfx->hdc,c);
	setColor(gfx->hdc,c);

//fprintf(out,"HoroscopeChartPage::paintPlanets(1)\n");
//fflush(out);
	c = aMath::round((aMath::PI*r3)/h.planets())+1;
	for(i=0; i<h.planets(); i++) positionPlanet(i,pl,pa,0.0,fs,r3,h,i,c);

	for(i=0; i<h.planets(); i++) {
		p = h.planetID(i);
		if(p==ASTRO_ASCENDANT || p==ASTRO_MC) continue;
		a1 = DTR*(ascendant-h.planetLongitude(i)),a2 = pa[i],*str = 'a'+p;
//fprintf(out,"HoroscopeChartPage::paintPlanets(i=%d,p=%d,a1=%lf,a2=%lf,l=%d,t=%d)\n",i,p,a1,a2,pl[i].x,pl[i].y);
//fflush(out);
		if(r2) drawLine(xc-fs3-aMath::round(cos(a1)*r1),yc-aMath::round(sin(a1)*r1),xc-fs3-aMath::round(cos(a2)*r2),yc-aMath::round(sin(a2)*r2));
		TextOut(gfx->hdc,pl[i].x,pl[i].y,str,1);
	}
//fprintf(out,"HoroscopeChartPage::paintPlanets(3)\n");
//fflush(out);
*/
}

void HoroscopeChartPage::paintAspects(int r,Horoscope &h1,Horoscope &h2,bool syn) {
/*	int i,j,s1,s2,a;
	double asc = ascendant,p1,p2;
	for(i=0; i<h1.planets(); i++)
		for(j=0; j<=(syn? h1.planets() : i); j++) if(i!=j || syn) {
			p1 = h1.planetLongitude(i),p2 = h2.planetLongitude(j);
			s1 = h1.sign(i),s2 = h2.sign(j);
			a = h1.aspect(i,j);
			if(a>=ASTRO_CONJUNCTION && a<=ASTRO_OPPOSITION && aspectShow[a] &&
					(!aspectShow[13] || horoscope->findPattern(i,j))) {
				setColor(gfx->hdc,aspectColors[a]);
				p1 = aMath::PI*((asc-p1)/180);
				p2 = aMath::PI*((asc-p2)/180);
				drawLine(xc-aMath::round(cos(p1)*r),yc-aMath::round(sin(p1)*r),
					xc-aMath::round(cos(p2)*r),yc-aMath::round(sin(p2)*r));
			}
		}
*/
}


void HoroscopeChartPage::writeHoroscope(aString &str) {
app.printf("HoroscopeChartPage::writeHoroscope(%s)",horoscope->profile.name());

	str.append("<html>\n"
		"<head>\n"
//		"<style>").include(HTML_PATH "style.css").include(HTML_PATH "style.astro.css").append("</style>\n"
//		"<script>").include(HTML_PATH "script.js").append("</script>\n"
		"<link type=\"text/css\" rel=\"stylesheet\" href=\"style.css\" />\n"
		"<link type=\"text/css\" rel=\"stylesheet\" href=\"style.astro.css\" />\n"
		"<script src=\"script.js\"></script>\n"
		"</head>\n\n"
		"<body>\n");
app.printf("HoroscopeChartPage::writeHoroscope(1)");
	/*if(horoscope->rels[0]) {
		str.append("<h3>").append(horoscope->profile.name()).append("</h3>\n");
		writeChartInfo(str,*horoscope->rels[0],1);
		if(horoscope->rels[1]) writeChartInfo(str,*horoscope->rels[1],2);
	} else {*/
		str.append("<h3>").append("Natalt Horoskop").append("</h3>\n");
		writeChartInfo(str,*horoscope);
	//}
app.printf("HoroscopeChartPage::writeHoroscope(2)");
	if(horoscope->style()==HOROSCOPE_SYNASTRY) {
		writeAspectTable(str);
//		writePatterns(str);
	} else {
		writeFactors(str);
		writePlanetTable(str);
		writeHouseTable(str);
		writeAspectTable(str);
		writePatterns(str);
	}
	str.append("</body>\n</html>\n");
app.printf("HoroscopeChartPage::writeHoroscope(3)");
}

void HoroscopeChartPage::writeChartInfo(aString &str,Horoscope &h,int col) {
	Profile &p = h.profile;
	str.append("\n<div class=\"");
	if(col>0) str.append("profile").append(col);
	char lon[32],lat[32];
	p.printLongitude(lon,app.get("londirs"));
	p.printLatitude(lat,app.get("latdirs"));
	str.append("\"><h5>").append(p.name()).append("</h5></div>\n").
		appendf("%d.%02d.%02d %02d:%02d",p.year(),p.month(),p.day(),p.hour(),p.minute()).
		append("<br>\n").append(p.location()).append(", ").
		append(lon).append(", ").append(lat).
		append("<br>\n<a href=\"symbol://").append(Horoscope::labelCode(ASTRO_JULIAN_DAY)).append("\">").
		append(app.occult.astroLabel(ASTRO_JULIAN_DAY)).append("</a>: ").
		append(h.julianDay()+h.deltaTime()/86400.0).append(", dT ").append(h.deltaTime()).append("\n\n");
}

void HoroscopeChartPage::writePlanetTable(aString &str) {
	str.append("<table class=\"planets\" cellspacing=\"0\">\n"
		"\t<tr>\r\n\t<th class=\"plt1\"><a href=\"symbol://").
			append(Horoscope::conceptCode(ASTRO_PLANETS)).append("\">").
			append(app.occult.conceptNamePlur(ASTRO_PLANETS)).append("</a>:</th>\n"
		"\t<th class=\"plt2\"><a href=\"symbol://").
			append(Horoscope::labelCode(ASTRO_LONGITUDE)).append("\">").
			append(app.occult.astroLabel(ASTRO_LONGITUDE)).append("</a>:</th>\n"
		"\t<th class=\"plt3\"><a href=\"symbol://").append(Horoscope::conceptCode(ASTRO_ZODIAC)).
			append("\">").append(app.occult.conceptNamePlur(ASTRO_ZODIAC)).append("</a>:</th>\n"
		"\t<th>&nbsp;</th>\n"
		"\t</tr>\n");
	for(int i=0,s,p; i<horoscope->planets(); i++) {
		p = horoscope->planetID(i),s = horoscope->planetSign(i);
		if(p==ASTRO_ASCENDANT || p==ASTRO_MC) continue;
		str.append("\t<tr>\n"
			"\t<td class=\"plt1\"><a href=\"symbol://").
				append(Horoscope::planetInZodiacCode(p,s)).append("\"><span class=\"astro1\">").append((char)('a'+p)).
				append("</span> ").append(app.occult.planetName(p)).append("</a></td>\n"
			"\t<td class=\"plt2\">").append(hms(horoscope->planetLongitude(i))).append("</td>\n"
			"\t<td class=\"plt3\"><a href=\"symbol://").append(Horoscope::planetInZodiacCode(p,s)).
				append("\"><span class=\"astro1 zodiac").append(s).append("\">").append((char)('A'+s-1)).
				append("</span> ").append(app.occult.zodiacName(s)).append("</a></td>\n"
			"\t</tr>\n");
	}
	str.append("</table>\n\n");
}

void HoroscopeChartPage::writeHouseTable(aString &str) {
	str.append("<table class=\"houses\" cellspacing=\"0\">\n"
		"\t<tr>\n"
		"\t<th class=\"hst1\"><a href=\"symbol://").append(Horoscope::conceptCode(ASTRO_HOUSES)).append("\">").
			append(app.occult.conceptNamePlur(ASTRO_HOUSES)).append("</a> (<a href=\"symbol://").
			append(Horoscope::houseSystemCode(ASTRO_PLACIDUS)).append("\">").append(app.occult.houseSystemName(ASTRO_PLACIDUS)).
			append("</a>):</th>\n"
		"\t<th class=\"hst2\"><a href=\"symbol://").append(Horoscope::labelCode(ASTRO_LONGITUDE)).append("\">").
			append(app.occult.astroLabel(ASTRO_LONGITUDE)).append("</a>:</th>\n"
		"\t<th class=\"hst3\"><a href=\"symbol://").append(Horoscope::conceptCode(ASTRO_ZODIAC)).append("\">").
			append(app.occult.conceptNamePlur(ASTRO_ZODIAC)).append("</a>:</th>\n"
		"\t<th>&nbsp;</th>\n"
		"\t</tr>\n");
	for(int i=1,s; i<=12; i++) {
		s = horoscope->houseSign(i);
		str.append("\t<tr>\n"
			"\t<td class=\"hst1\"><a href=\"symbol://").append(Horoscope::houseInZodiacCode(i,s)).append("\">").
				append(app.occult.houseName(i)).append("</a></td>\n"
			"\t<td class=\"hst2\">").append(hms(horoscope->houseCusp(i))).append("</td>\n"
			"\t<td class=\"hst3\"><a href=\"symbol://").append(Horoscope::houseInZodiacCode(i,s)).append("\"><span class=\"astro1 zodiac").
				append(s).append("\">").append((char)('A'+s-1)).append("</span> ").append(app.occult.zodiacName(s)).
				append("</a></td>\n"
			"\t</tr>\n");
	}
	str.append("</table>\n\n");
}

void HoroscopeChartPage::writeFactors(aString &str) {
	str.append("<table class=\"factors\" cellspacing=\"0\">\n"
		"\t<tr>\n"
		"\t<td class=\"fct1\"><a href=\"symbol://").append(Horoscope::factorCode(ASTRO_RULER_PLANET)).append("\">").
			append(app.occult.factorName(ASTRO_RULER_PLANET)).append("</a>:</td>\n"
		"\t<td class=\"fct2 astro1\"><a href=\"symbol://").
			append(Horoscope::planetFactorCode(horoscope->rulingPlanet(),ASTRO_RULER_PLANET)).
			append("\">").append((char)('a'+horoscope->rulingPlanet())).append("</a></td>\n"
		"\t</tr>\n"
		"\t<tr>\n"
		"\t<td class=\"fct1\"><a href=\"symbol://").append(Horoscope::factorCode(ASTRO_RULER_HOUSE)).append("\">").
			append(app.occult.factorName(ASTRO_RULER_HOUSE)).append("</a>:</td>\n"
		"\t<td class=\"fct2\"><a href=\"symbol://").append(Horoscope::houseFactorCode(horoscope->rulingHouse(),ASTRO_RULER_HOUSE)).append("\">").
			append(app.occult.houseName(horoscope->rulingHouse())).append("</a></td>\n"
		"\t</tr>\n"
		"\t<tr>\n"
		"\t<td class=\"fct1\"><a href=\"symbol://").append(Horoscope::factorCode(ASTRO_ASCENDING)).append("\">").
			append(app.occult.factorName(ASTRO_ASCENDING)).append("</a>:</td>\n"
		"\t<td class=\"fct2\"><span class=\"astro1\">");
	for(int i=0,p; i<horoscope->planets(); i++) if(horoscope->planetIsRising(i)) {
		p = horoscope->planetID(i);
		str.append("<a href=\"symbol://").append(Horoscope::planetFactorCode(p,ASTRO_ASCENDING)).
			append("\">").append((char)('a'+p)).append("</a>");
	}
	str.append("</span></td>\n"
		"\t</tr>\n"
		"\t<tr>\n"
		"\t<td class=\"fct1\"><a href=\"symbol://").append(Horoscope::factorCode(ASTRO_ANGULAR)).append("\">").
			append(app.occult.factorName(ASTRO_ANGULAR)).append("</a>:</td>\n"
		"\t<td class=\"fct2\"><span class=\"astro1\">");
	for(int i=0,p; i<horoscope->planets(); i++) if(horoscope->planetIsAngular(i)) {
		p = horoscope->planetID(i);
		str.append("<a href=\"symbol://").append(Horoscope::planetFactorCode(p,ASTRO_ANGULAR)).
			append("\">").append((char)('a'+p)).append("</a>");
	}
	str.append("</td>\n"
		"\t</tr>\n"
		"\t</tr>\n"
		"\t<tr>\n"
		"\t<td class=\"fct1\"><a href=\"symbol://").append(Horoscope::factorCode(ASTRO_MRECEPTIVE)).append("\">").
			append(app.occult.factorName(ASTRO_MRECEPTIVE)).append("</a>:</td>\n"
		"\t<td class=\"fct2\">");
	for(int i=0,p1,p2; i<horoscope->planets(); i++) if(horoscope->planetMutualReceptive(i)) {
		p1 = horoscope->planetID(i);
		p2 = astro_ruling_planets[horoscope->planetSign(p1)];
		str.append("<a href=\"symbol://").append(Horoscope::mutualReceptiveCode(p1,p2)).
				append("\"><span class=\"astro1\">").append((char)('a'+p1)).append("</span>/<span class=\"astro1\">").
				append((char)('a'+p2)).append("</span></a> ");
	}
	str.append("</td>\n"
		"\t</tr>\n"
		"</table>\n\n");
}

void HoroscopeChartPage::writeAspectTable(aString &str) {
	str.append("<table class=\"aspects\" cellspacing=\"0\">\n"
		"\t<tr>\n"
		"\t<th><a href=\"symbol://").append(Horoscope::conceptCode(ASTRO_ASPECTS)).append("\">").
			append(app.occult.conceptNamePlur(ASTRO_ASPECTS)).append("</a>:</th>\n"
		"\t</tr>\n"
		"\t<tr>\n"
		"\t<td>\n"
		"\t\t<table cellspacing=\"0\">\n"
		"\t\t\t<tr>\n");
	int i,a,n,p,j;
	if(horoscope->style()==HOROSCOPE_SYNASTRY) {
		n = horoscope->planets();
		for(i=0; i<n; i++)
			str.append("\t\t\t<td class=\"block1 astro1 profile1\"><a href=\"symbol://").
				append(Horoscope::planetCode(horoscope->planetID(i))).append("\">").
				append((char)('a'+horoscope->planetID(i))).append("</a></td>\n");
		str.append("\t\t\t</tr>\n");
		for(i=0; i<horoscope->planets(); i++) {
			p = horoscope->planetID(i);
			str.append("\t\t\t<tr>\n");
			for(j=0; j<=n; j++) {
				a = horoscope->aspect(j,i);
				if(j==n) str.append("\t\t\t<td class=\"block2 astro1 profile2\"><a href=\"symbol://").
					append(Horoscope::planetCode(p)).append("\">").append((char)('a'+p)).append("</a><td>\n");
				else {
					str.append("\t\t\t<td class=\"block").append(i<horoscope->planets()-1? 3 : 4);
					if(a>=ASTRO_CONJUNCTION && a<=ASTRO_OPPOSITION
						// && aspectShow[a] && (!aspectShow[13] || horoscope->findPattern(i,j))
							)
						str.append("\"><a href=\"symbol://").
							append(Horoscope::aspectPlanetToPlanetCode(horoscope->planetID(j),horoscope->planetID(i),a)).
							append("\" class=\"astro1 aspect").append(a).append("\">").append((char)('N'+a)).append("</a>");
					else str.append("\">&nbsp;");
					str.append("</td>\n");
				}
			}
			str.append("\t\t\t</tr>\n");
		}
	} else {
		for(i=0; i<horoscope->planets(); i++) {
			p = horoscope->planetID(i);
			n = i<15? i : 15;
			str.append("\t\t\t<tr>\n");
			for(j=0; j<=n; j++) {
				a = horoscope->aspect(i,j);
				if(i==0 || j==n) str.append("\t\t\t<td class=\"block").append(i==0? '1' : '2').
					append(" astro1\"><a href=\"symbol://").append(Horoscope::planetCode(p)).append("\">").
					append((char)('a'+p)).append("</a></td>\n");
				else {
					str.append("\t\t\t<td class=\"block").append(i<horoscope->planets()-1? 3 : 4);
					if(a>=ASTRO_CONJUNCTION && a<=ASTRO_OPPOSITION
						// && aspectShow[a] && (!aspectShow[13] || horoscope->findPattern(i,j))
							)
						str.append("\"><a href=\"symbol://").
							append(Horoscope::aspectPlanetToPlanetCode(horoscope->planetID(j),horoscope->planetID(i),a)).
							append("\" class=\"astro1 aspect").append(a).append("\">").append((char)('N'+a)).append("</a>");
					else str.append("\">&nbsp;");
					str.append("</td>\n");
				}
			}
			str.append("\t\t\t</tr>\n");
		}
	}
	str.append("\t\t</table>\n"
		"\t</tr>\n"
		"\t</td>\n"
		"</table>\n\n");
}

void HoroscopeChartPage::writePatterns(aString &str) {
//app.printf("HoroscopeChartPage::writePatterns(%s)",horoscope->profile.name());

/*	int i,j,k,p1,v = 0;
	unsigned int *p,m,n,pl;
	char h = 1,pat[horoscope->planets()],*s;
	symbol_t c;
	for(i=0; i<ASTRO_NUM_PATTERNS; i++) {
		p = horoscope->aspectPattern(i);
		if((m=horoscope->aspectPatterns(i))) for(j=0,n=(1<<(m-1)); j<(int)m && n; j++,n>>=1) {
			if(h) {
				str.append("<table class=\"patterns\" cellspacing=\"0\">\n"
					"\t<tr>\n"
					"\t<th class=\"ptt1\"><a href=\"symbol://").append(Horoscope::conceptCode(ASTRO_PATTERNS)).append("\">").
						append(app.occult.concept(ASTRO_PATTERNS,1)).append(":</th>\n"
					"\t<th class=\"ptt2\">&nbsp;</th>\n"
					"\t<th class=\"ptt3\">&nbsp;</th>\n"
					"\t<th>&nbsp;</th>\n"
					"\t</tr>\n");
				h = 0;
			}
			for(k=0,pl=0,s=pat; k<horoscope->planets(); k++) if(p[k]&n) {
				p1 = horoscope->planetID(k),*s++ = (char)('a'+p1);
				if(!pl || (p[k]&(n<<16))) pl = k;
			}
			*s = 0;
			if(i==ASTRO_AP_TSQUARE || i==ASTRO_AP_GCROSS) {
				v = Horoscope::qualities[(int)horoscope->planetSign(pl)];
				s = app.occult.quality(v),c = Horoscope::patternQualityCode(i,v);
			} else if(i==ASTRO_AP_GTRINE) {
				v = Horoscope::elements[(int)horoscope->planetSign(pl)];
				s = app.occult.element(v,OCCULT_ASTRO),c = Horoscope::patternElementCode(i,v);
			} else s = 0,c = Horoscope::patternCode(i);
			str.append("\t<tr>\n"
				"\t<td class=\"ptt1\"><a href=\"symbol://").append(c).append("\">").append(app.occult.pattern(i));
			if(s) str.append(", ").append(s);
			str.append("</a></td>\n</td>\n"
				"\t<td class=\"ptt2 astro1\"><a href=\"symbol://").append(c).append("\">").
					append(pat).append("</a></td>\n");
app.printf("HoroscopeChartPage::writePatterns(i=%d,*p=%u,n=%u,pl=%u,sign=%u,v=%d)",i,*p,n,pl,horoscope->planetSign(pl),v);
			str.append("\t</tr>\n");
		}
	}
	if(!h) str.append("</table>\n\n");*/
}


void HoroscopeChartPage::positionPlanet(int n,GdkRectangle *r,double *an,double a,int fs,int r1,Horoscope &h,int l,int c) {
	int i,p = h.planetID(n);
//app.printf("HoroscopeChartPage::positionPlanet(n=%d,p=%d,%s,l=%d,c=%d)",n,p,app.occult.planetID(p),l,c);
	if(p==ASTRO_ASCENDANT || p==ASTRO_MC) return;
	int fs2 = fs/2,fs3 = fs/10;
	double a1 = an[n]+a;
	GdkRectangle p1 = { -fs2+fs3-aMath::round(cos(a1)*r1),-fs2+fs3-aMath::round(sin(a1)*r1),fs-(fs3<<1),fs-(fs3<<1) };
	r[n] = p1,an[n] += a;
	if(--c && (i=intersectPlanet(n,p1,r,l))>-1) {
		double h1 = DTR*(ascendant-h.planetLongitude(n)),h2 = DTR*(ascendant-h.planetLongitude(i));
		bool cw = fabs(h1-h2)>aMath::PI? h1<h2 : h1>h2;
		double a3 = 0.5*DTR,a4 = fabs(a1-h1)+a3;
		if(a4>a3*3) a4 = a3*3;
		positionPlanet(i,r,an,cw? -a3 : a3,fs,r1,h,l,c);
		positionPlanet(n,r,an,cw? a4 : -a4,fs,r1,h,l,c);
	}
}


int HoroscopeChartPage::intersectPlanet(int n,GdkRectangle &r,GdkRectangle *l,int len) {
	for(int i=0; i<len; i++) if(i!=n) {
		GdkRectangle &r2 = l[i];
		if(r.x<r2.x+r2.width && r.y<r2.y+r2.height &&
			r.x+r.width>r2.x && r.y+r.height>r2.y) return i;
	}
	return -1;
}

void HoroscopeChartPage::clearPlanetLocations(Horoscope &h,GdkRectangle *r,double *an) {
	memset(r,0,h.planets()*sizeof(GdkRectangle));
	if(an) for(int i=0; i<h.planets(); i++) an[i] = DTR*(ascendant-h.planetLongitude(i));
}

int HoroscopeChartPage::mouseMove(int x,int y,GdkPoint *drag,int params) {
	return findPoint(x,y);
}

int HoroscopeChartPage::mouseDown(int x,int y,int params) {
	if((params>>8)>1) return 0;
	int n = findPoint(x,y);
	if(n==-1) return 1;
	symbol_t c = 0;
	if(n>=ASTRO_ARIES && n<=ASTRO_PISCES) c = Astrology::zodiacCode(n);
	 else if(n>ASTRO_PISCES)
		n = horoscope->planetID(n-ASTRO_PISCES-1),c = Astrology::planetCode(n);
	if(c) {
app.printf("HoroscopeChartPage::mouseDown(n=%d,c=%I64d)",n,c);
		//TextMDI::loadDocument(c);
	}
	return 0;
}



int HoroscopeChartPage::findPoint(int x,int y) {
	int i;
	GdkRectangle *r;
	for(i=ASTRO_PISCES,r=&zodiacLocations[i]; i>=ASTRO_ARIES; i--,r=&zodiacLocations[i])
		if(x>=r->x && y>=r->y && x<=r->x+r->width && y<=r->y+r->height) return i;
	for(i=horoscope->planets()-1,r=&planetLocations1[i]; i>=0; i--,r=&planetLocations1[i])
		if(x>=r->x && y>=r->y && x<=r->x+r->width && y<=r->y+r->height) return ASTRO_PISCES+1+i;
	return -1;
}


const char *HoroscopeChartPage::hms(double d) {
//app.printf("HoroscopeChartPage::hms(%lf)",d);
	static char str[11];
	if(d<0) d = 30-fmod(fabs(d),30);
	double nl = d>=0 && d<30? d : fmod(d,30);
	int h,m,s;
	if(nl<1) h = 0;
	else h = (int)nl,nl -= h;
	m = (int)(nl*60);
	s = aMath::round(((nl*60)-m)*60);
//app.printf("HoroscopeChartPage::hms(h=%d,m=%d,s=%d)",h,m,s);
	sprintf(str,"%d°%02d'%02d\"",h,m,s);
	return str;
}



